unless defined?(RediPress)
  raise "You can't load this file. Please load the redipress file instead."
end

require 'sshkit'
require 'sshkit/dsl'

module RediPress
  module Configuration
    # This class is the basis of a configuration
    #
    class Base
      # Include the SSH Kit DSL
      #
      include SSHKit::DSL

      # Add class level functionality
      #
      class << self
        # Set a name for the configuration
        #
        # Arguments:
        #   name: (String)
        #
        # Example:
        #   >> class Test < RediPress::Configuration
        #   >>   name "Test"
        #   >> end
        #
        def name(name)
          @name = name
        end

        # Get the name of the configuration
        #
        # Example:
        #   >> configuration.class._name
        #   => "Test"
        #
        def _name
          @name
        end

        # Add a parameter to the configuration
        #
        # Arguments:
        #   slug: (String)
        #
        # Example:
        #   >> class Test < RediPress::Configuration
        #   >>   parameter :username do
        #   >>     name 'Username'
        #   >>     validation /^[a-z]{4,}$/
        #   >>   end
        #   >> end
        #
        def parameter(slug, &block)
          return nil if slug.nil?

          @parameters ||= []

          return @parameters if @parameters.map { |p| p.slug }.include?(slug)

          parameter = RediPress::Parameter.new(slug)
          parameter.instance_eval(&block) if block_given?

          @parameters << parameter
        end

        # Get the array of parameters for the configuration
        #
        # Example:
        #   >> configuration.class._parameters
        #   => [#<RediPress::Configuration::Parameter:0x00000000000000>]
        #
        def _parameters
          @parameters
        end
      end

      # Get the slug of the configuration
      #
      # Example:
      #   >> configuration.slug
      #   => "test"
      #
      def slug
        RediPress::Configuration.slug_for(self.class)
      end

      # Get the name of the configuration
      #
      # Example:
      #   >> configuration.name
      #   => "Test"
      #
      def name
        self.class._name
      end

      # Get the parameters for the configuration
      #
      # Example:
      #   >> configuration.parameters
      #   => [#<RediPress::Configuration::Parameter:0x00000000000000>]
      #
      def parameters
        self.class._parameters
      end

      # Convert the class to a string
      #
      # Example:
      #   >> configuration.to_s
      #   => 'Test'
      #
      def to_s
        name
      end

      protected

      # Check if the configuration is compatible with the server
      #
      # Arguments:
      #   host: (SSHKit::Host)
      #   options: (Hash)
      #
      # Example:
      #   >> configuration.compatible?(host, options)
      #   => true
      #
      def compatible?(host, options)
        true
      end

      # Configure the server
      # This method should return a hash with info to display (if needed) or nil
      #
      # Arguments:
      #   host: (SSHKit::Host)
      #   options: (Hash)
      #
      # Example:
      #   >> configuration.configure(host, options)
      #   => nil
      #
      # Raises:
      #   RediPress::ConfigurationNotImplemented: If this method is not overriden
      #
      def configure(host, options)
        raise RediPress::ConfigurationNotImplemented
      end

      # Fail with an error
      #
      # Arguments:
      #   error: (String)
      #
      # Example:
      #   >> configuration.fail("Test error")
      #   => nil
      #
      # Raises:
      #   RediPress::ConfigurationFailed: When this method is called
      #
      def fail(error)
        raise RediPress::ConfigurationFailed.new(self, error)
      end
    end
  end
end
